import random
import queue


由于具有对称性，只讨论某一个方向就可以了
1.buy 不可以触发trade
直接放入buy的order队列，同时检查是否需要更新top_bid_px

2.buy 可以触发trade
a. buy  order的 vol < top_ask_vol， buy端的book不变化 ，ask端的top_ask_vol变化
b. buy  order的 vol == top_ask_vol， buy端的book不变化 ，ask端的top_ask_vol 和 top_ask_px变化
c. buy  order的 vol > top_ask_vol,
c1: ask端能吃掉 buy order的 全部 vol,  buy端的book不变化, ask端的top_ask_vol 和 top_ask_px变化
c2: ask端不能吃掉 buy order的 全部 vol, buy端的book和ask端的book变化 buy端的buy_top_Px = buy_order_px, buy_top_vol = buy_order_vol - trade_vol
ask端的ask_top_Px = 第一个大于buy_order_px的order的px, ask_top_vol = 第一个大于buy_order_px的order的 vol + 已累积的 - buy_order_vol


class HOrder:
    def __init__(self):
        self.order_id = 0
        self.px = 0
        self.side = 0
        self.vol = 0
        self.seq = 0
        self.timestamp = 0

    def __lt__(self, other):
        return self.px < other.px


class HTrade:
    def __init__(self):
        self.ask_id = 0
        self.bid_id = 0
        self.px = 0
        self.vol = 0
        self.seq = 0
        self.timestamp = 0


q = queue.PriorityQueue()

order1 = HOrder()
order1.__init__()
print(order1.px)
#order1.px = round( random.uniform(1, 4 ), 2)
order1.px = 3.666
q.put((3.3, order1))


order2 = HOrder()
order2.__init__()
print(order1.px)
#order2.px = round( random.uniform(1, 4 ), 2)
order2.px = 3.5555
q.put((3., order2))


order3 = HOrder()
order3.__init__()
print(order1.px)
#order3.px = round( random.uniform(1, 4 ), 2)
order3.px = 3.333
q.put((3.0, order3))


#order1.px = 3.8
#q.put(3.8 , order1)

while not q.empty():

    print(q.get()[1].px)


class Generator:
    seq = 0

    def __init__(self):
        print(456)
        self.bid_top = 0
        self.ask_top = 0
        self.bid_seq = queue.PriorityQueue()
        self.ask_seq = queue.PriorityQueue()
        self.bid_quote = []
        self.ask_quote = []
        self.trade_quote = []
        self.seq = 0
        self.rest_ask_order = HOrder()
        self.rest_bid_order = HOrder()

    def generate(self, num=1000, pre_close=10):
        low_limit = pre_close * 0.9
        high_limit = pre_close * 1.1
        offset = float(high_limit - low_limit) / 100

        self.rest_ask_order.px = (low_limit + high_limit) / 2 + 0.1
        self.rest_ask_order.order_id = 1
        self.rest_ask_order.vol = 100
        self.rest_ask_order.seq = 2

        self.rest_bid_order.px = (low_limit + high_limit) / 2 - 0.1
        self.rest_bid_order.order_id = 3
        self.rest_bid_order.vol = 100
        self.rest_bid_order.seq = 4

        self.seq = 5

        self.ask_top = self.rest_ask_order.px
        self.bid_top = self.rest_bid_order.px
        for i in range(num):
            seed = random.random()
            order = HOrder()
            order.__init__()
            if seed > 0.7:
                order.side = 1  # buy
                #order.px = round( random.uniform(low_limit, self.bid_top + offset * 10 ), 2)
                value = random.uniform(low_limit, self.bid_top + offset * 10)
                order.px = round(value, 2)
                order.seq = self.seq
                order.order_id = self.seq
                self.seq = self.seq + 1
                order.vol = random.randint(100, 700)

                self.bid_quote.append(order)
                self.bid_seq.put((order.px, order))

                print("ask_top " + str(self.ask_top) +
                      " rest_ask_vol " + str(self.rest_ask_order.vol))
                print("bid_top " + str(self.bid_top) +
                      " rest_bid_vol " + str(self.rest_bid_order.vol))
                print("order px bid " + str(order.px) +
                      " bid vol " + str(order.vol))

                if self.bid_top == 0:
                    self.bid_top = order.px

                if self.bid_top < order.px:

                    if order.px < self.ask_top:
                        self.bid_top = order.px
                        continue
                    # 如果ask还没有数据，则不产生交易数据
                    if self.rest_ask_order.vol == 0 and self.ask_seq.empty():
                        self.bid_top = order.px
                        self.ask_top = order.px
                        continue

                    curr = HOrder()
                    # 根据px和vol 查看能达到对手的哪个位置
                    seq_ask = {}
                    cnt_vol = self.rest_ask_order.vol
                    curr.px = self.ask_top

                    trade_px = 0
                    while (not self.ask_seq.empty()) and cnt_vol < order.vol:
                        curr = self.ask_seq.get()[1]
                        # 价格达到了上限 跳出
                        if curr.px > order.px:
                            break
                        cnt_vol = cnt_vol + curr.vol
                        seq_ask.setdefault(curr.seq, curr)
                    # bid 的 vol 全被ask 吃掉 ,bid_top不用动
                    if cnt_vol > order.vol:

                        #rest_ask_px = curr.px
                        self.ask_top = curr.px
                        trade_px = curr.px

                        self.rest_ask_order.vol = cnt_vol - order.vol
                        self.rest_ask_order.order_id = curr.order_id
                        self.rest_ask_order.seq = curr.seq
                        self.rest_ask_order.px = curr.px
                    # bid 的 部分被ask 吃掉, ask_top 和 bid_top 都需要修改  此时的ask_top, bid_top是吃不动的
                    if cnt_vol < order.vol:
                        self.rest_bid_order.vol = order.vol - cnt_vol
                        self.bid_top = order.px

                        # ask 的剩余即就是最近被出队列的但是不能吃掉的order
                        self.rest_ask_order.vol = curr.vol
                        self.rest_ask_order.order_id = curr.order_id
                        self.rest_ask_order.seq = curr.seq
                        self.rest_ask_order.px = curr.px

                        trade_px = order.px

                    if cnt_vol == order.vol:
                        print("need to do ")
                    # 接着生成trade 有几个 ask则生成几个 trade
                    if trade_px == 0:
                        print("excetion")
                    print("----------------trade happpen----------------")

                    print("ask_top " + str(self.ask_top) +
                          " rest_ask_vol " + str(self.rest_ask_order.vol))
                    print("bid_top " + str(self.bid_top) +
                          " rest_bid_vol " + str(self.rest_bid_order.vol))
                    print("order px bid " + str(order.px) +
                          " bid vol " + str(order.vol))
                    if len(seq_ask) == 0:
                        trade = HTrade()
                        curr_element = self.rest_ask_order
                        trade.seq = curr_element.seq
                        # 成交价应该是本方最优
                        trade.px = trade_px
                        trade.bid_id = order.order_id
                        trade.ask_id = curr_element.order_id
                        trade.vol = curr_element.vol
                        self.trade_quote.append(trade)

                        continue
                    for ele in seq_ask:
                        trade = HTrade()
                        curr_element = seq_ask[ele]
                        trade.seq = curr_element.seq
                        # 成交价应该是本方最优
                        trade.px = trade_px
                        trade.bid_id = order.order_id
                        trade.ask_id = curr_element.order_id
                        trade.vol = curr_element.vol
                        self.trade_quote.append(trade)

            else:
                order.side = 0  # ask
                #order.px = round( random.uniform(self.ask_top - offset * 10, high_limit ), 2)
                value = random.uniform(self.ask_top - offset * 10, high_limit)
                order.px = round(value, 2)
                order.order_id = self.seq
                order.seq = self.seq
                self.seq = self.seq + 1
                order.vol = random.randint(100, 700)

                self.ask_quote.append(order)
                self.ask_seq.put((order.px, order))

                if self.ask_top == 0:
                    self.ask_top = order.px

                print("ask_top " + str(self.ask_top) +
                      " rest_ask_vol " + str(self.rest_ask_order.vol))
                print("bid_top " + str(self.bid_top) +
                      " rest_bid_vol " + str(self.rest_bid_order.vol))
                print("order px bid " + str(order.px) +
                      " bid vol " + str(order.vol))

                if order.px < self.ask_top:

                    if order.px > self.bid_top:
                        self.ask_top = order.px
                        continue

                    # 如果bid还没有数据，则不产生交易数据
                    if self.rest_bid_order.vol == 0 and self.bid_seq.empty():
                        self.bid_top = order.px
                        self.ask_top = order.px
                        continue

                    curr = HOrder()
                    # 根据px和vol 查看能达到对手的哪个位置
                    seq_bid = {}
                    cnt_vol = self.rest_bid_order.vol
                    curr.px = self.bid_top

                    trade_px = 0
                    while (not self.bid_seq.empty()) and cnt_vol < order.vol:
                        curr = self.bid_seq.get()[1]
                        # 价格达到了上限 跳出
                        if curr.px > order.px:
                            break
                        cnt_vol = cnt_vol + curr.vol
                        seq_bid.setdefault(curr.seq, curr)
                    # ask 的 vol 全被bid 吃掉 ,ask_top不用动
                    if cnt_vol > order.vol:
                        self.rest_bid_order.vol = cnt_vol - order.vol
                        #rest_ask_px = curr.px
                        self.bid_top = curr.px
                        trade_px = curr.px

                        self.rest_bid_order.vol = cnt_vol - order.vol
                        self.rest_bid_order.order_id = curr.order_id
                        self.rest_bid_order.seq = curr.seq
                        self.rest_bid_order.px = curr.px
                    # ask 的 部分被bid 吃掉, ask_top 和 bid_top 都需要修改
                    if cnt_vol < order.vol:
                        self.rest_ask_order.vol = order.vol - cnt_vol
                        self.bid_top = order.px

                        # bid 的剩余即就是最近被出队列的但是不能吃掉的order
                        self.bid_top = curr.px

                        trade_px = order.px

                        self.rest_bid_order.vol = curr.vol
                        self.rest_bid_order.order_id = curr.order_id
                        self.rest_bid_order.seq = curr.seq
                        self.rest_bid_order.px = curr.px
                    # 接着生成trade 有几个 ask则生成几个 trade
                    if trade_px == 0:
                        print("excetion")
                    print("----------------trade happpen----------------")

                    print("ask_top " + str(self.ask_top) +
                          " rest_ask_vol " + str(self.rest_ask_order.vol))
                    print("bid_top " + str(self.bid_top) +
                          " rest_bid_vol " + str(self.rest_bid_order.vol))
                    print("order px bid " + str(order.px) +
                          " bid vol " + str(order.vol))
                    if len(seq_bid) == 0:
                        trade = HTrade()
                        curr_element = self.rest_bid_order
                        trade.seq = curr_element.seq
                        # 成交价应该是本方最优
                        trade.px = trade_px
                        trade.bid_id = order.order_id
                        trade.ask_id = curr_element.order_id
                        trade.vol = curr_element.vol
                        self.trade_quote.append(trade)

                        continue
                    for ele in seq_bid:
                        trade = HTrade()
                        curr_element = seq_bid[ele]
                        trade.seq = curr_element.seq
                        # 成交价应该是本方最优
                        trade.px = trade_px
                        trade.bid_id = order.order_id
                        trade.ask_id = curr_element.order_id
                        trade.vol = curr_element.vol
                        self.trade_quote.append(trade)

            i = i + 1


gen = Generator()
gen.__init__()
gen.generate()
# for ele in gen.trade_quote:
#    print("begin")
#    print(ele.px)
#    print(ele.seq)
print(456)
# 应该是只产生order,当出现价格越过对手价时,处理已有数据，并添加对应trade信息
